package kvsrv

import (
	"log"
	"sync"
)

const Debug = false

func DPrintf(format string, a ...interface{}) (n int, err error) {
	if Debug {
		log.Printf(format, a...)
	}
	return
}

type Log struct {
	id  int
	res string
}

type KVServer struct {
	mu      sync.Mutex
	kvTable map[string]string
	history map[string]*Log
	// Your definitions here.
}

func (kv *KVServer) Get(args *GetArgs, reply *GetReply) {
	// Your code here.
	kv.mu.Lock()
	defer kv.mu.Unlock()
	res, _ := kv.kvTable[args.Key]
	reply.Value = res
}

func (kv *KVServer) Put(args *PutAppendArgs, reply *PutAppendReply) {
	// Your code here.
	kv.mu.Lock()
	defer kv.mu.Unlock()
	if v, ok := kv.history[args.ClientId]; ok {
		if v.id == args.OpId {
			return
		}
	} else {
		kv.history[args.ClientId] = &Log{}
	}
	kv.kvTable[args.Key] = args.Value
	reply.Value = ""
	opLog := kv.history[args.ClientId]
	opLog.res = ""
	opLog.id = args.OpId
}

func (kv *KVServer) Append(args *PutAppendArgs, reply *PutAppendReply) {
	// Your code here.
	kv.mu.Lock()
	defer kv.mu.Unlock()
	if v, ok := kv.history[args.ClientId]; ok {
		if v.id == args.OpId {
			reply.Value = v.res
			return
		}
	} else {
		kv.history[args.ClientId] = &Log{}
	}
	res, _ := kv.kvTable[args.Key]
	opLog := kv.history[args.ClientId]
	opLog.res = res
	opLog.id = args.OpId
	kv.kvTable[args.Key] = res + args.Value
	reply.Value = res
}

func StartKVServer() *KVServer {
	kv := new(KVServer)

	// You may need initialization code here.
	kv.kvTable = make(map[string]string)
	kv.history = make(map[string]*Log)
	return kv
}
